package ink.tiptop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.trilead.ssh2.Connection;
import ink.tiptop.persist.domain.bo.LocalViewDto;
import ink.tiptop.persist.domain.entity.ZjfBaseServerInfoEntity;
import ink.tiptop.persist.domain.entity.ZjfModuleLocalEntity;
import ink.tiptop.persist.domain.entity.ZjfModuleLocalViewEntity;
import ink.tiptop.persist.domain.entity.ZjfServiceRemoteViewEntity;
import ink.tiptop.dto.req.local.view.*;
import ink.tiptop.enums.EResp;
import ink.tiptop.common.domain.WebworkResponse;
import ink.tiptop.dto.resp.local.ZjfModuleLocalViewInfo;
import ink.tiptop.common.cache.CacheAble;
import ink.tiptop.common.cache.CacheEvict;
import ink.tiptop.common.cache.ECaches;
import ink.tiptop.constant.Cmd;
import ink.tiptop.persist.dao.ZjfModuleLocalViewMapper;
import ink.tiptop.common.domain.req.PageRequest;
import ink.tiptop.common.domain.rsp.PageResponse;
import ink.tiptop.common.domain.rsp.Response;
import ink.tiptop.common.domain.rsp.SucceedResponse;
import ink.tiptop.service.*;
import ink.tiptop.utils.ssh.SshUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 本地模块结构视图(ZjfModuleLocalViewEntity)表服务实现类
 *
 * @author makejava
 * @since 2020-06-21 20:39:55
 */
@Service("zjfModuleLocalViewService")
@Slf4j
public class ZjfModuleLocalViewServiceImpl implements ZjfModuleLocalViewService {
    private static final String CACHE_KEY = "MODULE_VIEW";
    private static final String CACHE_CLEAR = CACHE_KEY + "*";
    // 维护一个排序字段映射,前端传递 PARENT -> 排序映射 parent
    private static final Map<String, String> orderByMap = new HashMap<>();
    private static final String ORDER_BY_FORMAT = "`%s` %s";

    static {
//        orderByMap.put("PARENT", "parent");
        orderByMap.put("NAME", "name");
        orderByMap.put("IGNORE", "ignore");
        orderByMap.put("REMOTE_NAME", "remote_id");
        orderByMap.put("LOCAL_NAME", "local_id");
        orderByMap.put("VERSION", "version");
    }

    @Resource
    private ZjfModuleLocalViewMapper zjfModuleLocalViewMapper;
    @Autowired
    private ZjfServiceRemoteViewService serviceRemoteViewService;
    @Autowired
    private ZjfAuthUserInfoService authUserInfoService;
    @Autowired
    private ZjfUserModuleVersionService userModuleVersionService;
    @Autowired
    private ZjfBaseServerInfoService baseServerInfoService;
    @Autowired
    private ZjfModuleLocalService moduleLocalService;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public ZjfModuleLocalViewEntity queryById(Integer id) {
        return this.zjfModuleLocalViewMapper.selectById(id);
    }

    @Override
    public List<ZjfModuleLocalViewEntity> queryAllByUser(String user) {
        ZjfModuleLocalViewEntity viewEntity = new ZjfModuleLocalViewEntity();
        viewEntity.setUser(user);
        return this.zjfModuleLocalViewMapper.selectList(new QueryWrapper<>(viewEntity));
    }

    /**
     * 新增数据
     *
     * @param zjfModuleLocalViewEntity 实例对象
     * @return 实例对象
     */
    @Override
    public ZjfModuleLocalViewEntity insert(ZjfModuleLocalViewEntity zjfModuleLocalViewEntity) {
        this.zjfModuleLocalViewMapper.insert(zjfModuleLocalViewEntity);
        return zjfModuleLocalViewEntity;
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.zjfModuleLocalViewMapper.deleteById(id) > 0;
    }

    @Override
    @CacheAble(desc = "模块本地视图缓存", keyPrefix = CACHE_KEY, type = ECaches.DAY)
    public Response list(QueryZjfModuleLocalViewRequest request) {
        // 获取查询参数
        ZjfModuleLocalViewEntity param = new ZjfModuleLocalViewEntity();
        BeanUtils.copyProperties(request, param);
        // 设置分页参数
        setOrderBy(request);
        Integer currPage = request.getOffset()/request.getCapacity() -1;
        Page<ZjfModuleLocalViewEntity> ePage = new Page<>(currPage, request.getCapacity(), true);

        Page<ZjfModuleLocalViewEntity> pageInfo = zjfModuleLocalViewMapper.selectPage(ePage, new QueryWrapper<>(param));
        // 组装响应参数,list
        List<ZjfModuleLocalViewInfo> responseList = getResponseList(pageInfo.getRecords(),request.getUser());

        return new PageResponse(responseList)
                .total(pageInfo.getTotal())
                .offset(request.getOffset());

    }

    protected void setOrderBy(PageRequest request) {
//        if (StringUtils.isNoneBlank(request.getSortType())
//                && StringUtils.isNoneBlank(request.getSortName())) {
//            // 这里直接设置了排序,比如 create_time  desc
//            String orderByString = String.format(ORDER_BY_FORMAT, orderByMap.get(request.getSortName()), request.getSortType());
//            PageHelper.orderBy(orderByString);
//        }
    }


    /**
     * 组装响应参数,这里其实是list,为了扩展 ,写成了Object
     *
     * @param voList
     * @return
     */
    private List<ZjfModuleLocalViewInfo> getResponseList(List<ZjfModuleLocalViewEntity> voList, String user) {

        List<ZjfModuleLocalViewInfo> infos = new ArrayList<>();
        ZjfModuleLocalViewInfo info;

        Map<Integer, String> remoteViewMap = getRemoteViewMap();
        Map<Integer, String> localModuleMap = getLocalModuleMap(user);
        Map<Integer, String> baseServerMap = getBaseServerMap();

        for (ZjfModuleLocalViewEntity entity : voList) {
            info = new ZjfModuleLocalViewInfo();
            BeanUtils.copyProperties(entity, info);
            String name = remoteViewMap.get(entity.getRemoteId());
            if (name != null) {
                info.setRemoteName(name);
            }
            String moduleName = localModuleMap.get(entity.getLocalId());
            if (moduleName != null) {
                info.setLocalName(moduleName);
            }
            String serverName = baseServerMap.get(entity.getServerId());
            if (serverName != null) {
                info.setServerName(serverName);
            }
            infos.add(info);
        }
        return infos;
    }

    private Map<Integer, String> getBaseServerMap() {
        // 查询远程视图信息
        List<ZjfBaseServerInfoEntity> zjfUserModuleVersionEntities = baseServerInfoService.queryAll();
        // 把服务ID映射成名称,装进map
        return zjfUserModuleVersionEntities.parallelStream().collect(
                Collectors.toMap(ZjfBaseServerInfoEntity::getId, et -> (et.getId() + "(" + et.getName() + ")")));
    }

    private Map<Integer, String> getLocalModuleMap(String user) {
        // 查询远程视图信息
        List<ZjfModuleLocalEntity> moduleLocalEntities = moduleLocalService.queryAllByUser(user);
        // 把服务ID映射成名称,装进map
        return moduleLocalEntities.parallelStream().collect(
                Collectors.toMap(ZjfModuleLocalEntity::getId, et -> (et.getId() + "(" + et.getName() + ")")));
    }

    private Map<Integer, String> getRemoteViewMap() {
        // 查询远程视图信息
        List<ZjfServiceRemoteViewEntity> entityList = serviceRemoteViewService.queryAll();
        // 把服务ID映射成名称,装进map
        return entityList.parallelStream().collect(
                Collectors.toMap(ZjfServiceRemoteViewEntity::getId, et -> (et.getId() + "(" + et.getName() + ")")));

    }

    @CacheEvict(key = CACHE_CLEAR, type = ECaches.DAY)
    public Response update(UpdateZjfModuleLocalViewRequest request) {
        ZjfModuleLocalViewEntity entity = new ZjfModuleLocalViewEntity();
        BeanUtils.copyProperties(request, entity);
        int rows = 0;
        try {
            rows = zjfModuleLocalViewMapper.updateById(entity);
        } catch (Exception e) {
            if (e instanceof DuplicateKeyException) {
                return WebworkResponse.failed(EResp.EServerInfo.ERROR_EXIST);
            }
        }
        if (rows > 0) {
            return WebworkResponse.SUCCEED;
        }
        return WebworkResponse.ERROR;
    }

    @CacheEvict(key = CACHE_CLEAR, type = ECaches.DAY)
    public Response delete(DeleteZjfModuleLocalViewRequest request) {
        List<Integer> reqIdList = request.getId().parallelStream().map(it -> Integer.parseInt(it)).collect(Collectors.toList());
        int rows = zjfModuleLocalViewMapper.deleteBatchIds(reqIdList);
        if (rows > 0) {
            return WebworkResponse.SUCCEED;
        }
        return WebworkResponse.ERROR;
    }

    @CacheEvict(key = CACHE_CLEAR, type = ECaches.DAY)
    public Response add(AddZjfModuleLocalViewRequest request) {
        // 查询服务器信息是否存在
        ZjfBaseServerInfoEntity serverInfoEntity = baseServerInfoService.queryById(request.getServerId());
        if (serverInfoEntity == null) {
            return WebworkResponse.failed(EResp.EServerInfo.ERROR_EXIST_NOT);
        }

        ZjfModuleLocalViewEntity entity = new ZjfModuleLocalViewEntity();
        entity.setLocalId(request.getLocalId());
        entity.setRemoteId(request.getRemoteId());
        int count = zjfModuleLocalViewMapper.selectCount(new QueryWrapper<>(entity));
        if (count > 0) {
            return WebworkResponse.failed(EResp.EViewLocal.ERROR_EXIST);
        }
        BeanUtils.copyProperties(request, entity);
        int rows = zjfModuleLocalViewMapper.insert(entity);
        if (rows > 0) {
            return WebworkResponse.SUCCEED;
        }
        return WebworkResponse.ERROR;
    }

    @Override
    @CacheEvict(key = CACHE_CLEAR, type = ECaches.DAY)
    public Response scan(ScanZjfModuleLocalViewRequest request) {
        // 1.校验参数是否都存在
        // 1.1用户
        authUserInfoService.checkUserExist(request.getUser());
        // 1.2版本
        userModuleVersionService.checkVersionExist(request.getUser(), request.getVersion());
        // 1.3服务器信息
        baseServerInfoService.checkServerExist(request.getServerId());
        // 这里可以用异步处理, 返回一个 可以入库的 result
        ZjfBaseServerInfoEntity serverInfoEntity = baseServerInfoService.queryById(request.getServerId());
        Connection conn = null;
        try {
            conn = baseServerInfoService.getConnection(serverInfoEntity);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            return WebworkResponse.failed(EResp.EServerInfo.ERROR_CONNECT_ERROR);
        }

        // 用户+版本获取本地模块列表
        ZjfModuleLocalEntity moduleLocalEntity = new ZjfModuleLocalEntity();
        moduleLocalEntity.setUser(request.getUser());
        moduleLocalEntity.setVersion(request.getVersion());
        List<ZjfModuleLocalEntity> list = moduleLocalService.queryAllByEntity(moduleLocalEntity);

        for (ZjfModuleLocalEntity module : list) {
            List<String> execList = null;
            try {
                execList = SshUtil.exec(conn, String.format(Cmd.FIND, request.getPathRemote(), module.getName() + "*.jar"));
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return WebworkResponse.failed(EResp.EServerInfo.ERROR_CONNECT_ERROR);
            }
            //  .../webwork/lib/webwork-0.0.1-SNAPSHOT.jar
            for (String exec : execList) {
                String[] rmtPath = exec.split("/");
                if (rmtPath.length < 3) {
                    log.info("搜索到的路径:{},因为长度过短而忽略", exec);
                    continue;
                }
                String lib = rmtPath[rmtPath.length - 2];
                if (!lib.toLowerCase().equals("lib")) {
                    log.error("搜索到的路径:{},不是标准的服务路径,跳过", exec);
                    continue;
                }
                // 用parent+name+serviceId 匹配完整的路径
                // /usr/local/easysw/apps/settlems-trade-api/settlems-trade-api2/lib/abc.jar
                // tail == /settlems-trade-api2/lib/abc.jar
                // rmtParent == /usr/local/easysw/apps/settlems-trade-api
                // rmtName == settlems-trade-api2
                String tail = rmtPath[rmtPath.length - 3] + "/" + rmtPath[rmtPath.length - 2] + "/" + rmtPath[rmtPath.length - 1];
                String rmtParent = exec.substring(0, exec.lastIndexOf(tail) - 1);
                ZjfServiceRemoteViewEntity serviceRemoteViewEntity = new ZjfServiceRemoteViewEntity();
                // /usr/local/easysw/apps/settlems-trade-api/settlems-trade-api/lib
                serviceRemoteViewEntity.setParent(rmtParent);
                // settlems-trade-api
                String rmtName = rmtPath[rmtPath.length - 3];
                serviceRemoteViewEntity.setName(rmtName);
                serviceRemoteViewEntity.setServerId(request.getServerId());
                ZjfServiceRemoteViewEntity respEntity = serviceRemoteViewService.queryByUniqueIndex(serviceRemoteViewEntity);
                if (respEntity == null) {
                    log.error("远程视图没有匹配到数据库中的数据:rmtParent:{},rmtName:{}", rmtParent, rmtName);
                    continue;
                }
                try {
                    // 插入数据
                    insertIntoModuleLocalView(request, module, respEntity);
                } catch (DuplicateKeyException e) {
                    log.error(e.getMessage(), e);
                    log.info("可能在同一个服务中出现了不同版本的依赖,当前执行到的exec:{},插入数据:{}", exec, rmtName);
                }
            }
        }
        return SucceedResponse.SUCCEED;
    }

    @Override
    public ZjfModuleLocalViewEntity getByUniqueIndex(LocalViewDto localViewDto) {
        ZjfModuleLocalViewEntity viewEntity = new ZjfModuleLocalViewEntity();
        viewEntity.setLocalId(localViewDto.getLocalId());
        viewEntity.setServerId(localViewDto.getServerId());
        viewEntity.setIgnore(localViewDto.getIgnore());
        List<ZjfModuleLocalViewEntity> zjfModuleLocalViewEntities = zjfModuleLocalViewMapper.selectList(new QueryWrapper<>(viewEntity));
        return zjfModuleLocalViewEntities.isEmpty() ? null : zjfModuleLocalViewEntities.get(0);
    }

    /**
     * 插入数据
     *
     * @param request
     * @param module
     * @param respEntity
     */
    private void insertIntoModuleLocalView(ScanZjfModuleLocalViewRequest request, ZjfModuleLocalEntity module, ZjfServiceRemoteViewEntity respEntity) {
        ZjfModuleLocalViewEntity entity = new ZjfModuleLocalViewEntity();
        entity.setRemoteId(respEntity.getId());
        // 如果两个都是
        if (respEntity.getIgnore() == 1 || respEntity.getIgnore() == 1) {
            entity.setIgnore(1);
        } else {
            entity.setIgnore(0);
        }
        entity.setLocalId(module.getId());
        entity.setServerId(request.getServerId());
        entity.setDesc("批量添加");
        entity.setUser(request.getUser());
        entity.setVersion(request.getVersion());
        int rows = zjfModuleLocalViewMapper.insert(entity);
        if (rows > 0) {
            log.info("插入成功,远程视图ID:{}", respEntity.getId());
        } else {
            log.info("插入失败,远程视图ID:{}", respEntity.getId());
        }
    }


}